package com.wxxymaker.edu.hook;

import com.blade.mvc.RouteContext;
import com.blade.mvc.hook.WebHook;
import com.blade.mvc.http.Request;
import com.blade.mvc.http.Response;
import com.wxxymaker.edu.model.entity.User;
import com.wxxymaker.edu.model.entity.UserToken;
import com.wxxymaker.edu.roles.AdminRoles;
import com.wxxymaker.edu.roles.IgnoreAuth;
import com.wxxymaker.edu.roles.StudentRoles;
import com.wxxymaker.edu.roles.TeacherRoles;
import com.wxxymaker.edu.utils.BaseKit;
import com.wxxymaker.edu.utils.Const;
import com.wxxymaker.edu.utils.TokenUtils;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

/**
 * @Author: soft
 * @Date: 2018/7/30 16:52
 * @Desc: 全局登录拦截器
 * 登录成功后,会将用户信息放到request中
 * 存入键值说明:
 *      role: 角色 1.学生 2.教师 3.管理员
 *      user: User实体实例,用户信息
 *      isLogin: 用户是否登录
 */
public class LoginHook implements WebHook {

    @Override
    public boolean before(RouteContext context) {
        Method   action   = context.routeAction();
        Class<?> target   = context.targetType();
        Request  request  = context.request();
        Response response = context.response();

        Annotation annotation = needAuth(action, target);
        String     token      = request.cookie(Const.TOKEN_KEY);
        context.attribute("role", -1);
        request.attribute("isLogin", false);
        if (annotation != null) {
            UserToken userToken = TokenUtils.auth(token);
            if (userToken != null) { // 1. 验证成功 表示用户是登录过了
                User tokenUser = userToken.getUser();
                Role role      = authRole(annotation, tokenUser);
                if (role.isCan()) { // 2. 验证登录用户的角色是否具有访问权限
                    /*User user = request.session().attribute(Const.USER_KEY);
                    if (user == null) { // session中没有用户信息 则添加

                    }*/ // 直接重新放入session
                    request.session().attribute(Const.USER_KEY, tokenUser);

                    // 将用户信息放入请求域
                    request.attribute("role", tokenUser.getRole());
                    request.attribute("user", tokenUser);
                    request.attribute("isLogin", true);
                    return true;
                } else {
                    response.redirect("/nopower");
                    return false;
                }
            }
        } else { // 不需要验证
            // 实现自动登录
            User user = request.session().attribute(Const.USER_KEY);
            if (user == null && token != null) {
                user = TokenUtils.getNoOverUserByToken(token);
                if (user != null ) request.session().attribute(Const.USER_KEY, user);
            }
            if (user != null) {
                request.attribute("role", user.getRole());
                request.attribute("user", user);
                request.attribute("isLogin", true);
            }
            return true;
        }

        String uri   = request.uri();
        String query = request.queryString();
        if (query != null && !"".equals(query)) {
            uri = uri + "?" + query;
        }
        response.redirect("/login?redirect=" + BaseKit.to(uri));
        return false;
    }

    /**
     * 根据注解类型设置权限等级
     * @param annotation 用户权限注解
     * @param user 用户信息
     * @return 返回这个角色是否通过验证和角色名
     */
    private Role authRole(Annotation annotation, User user) {
        Role role = new Role(false, "");
        if (annotation instanceof StudentRoles) {
            role.setCan(user.getRole() >= ((StudentRoles) annotation).role());
            role.setPower(((StudentRoles) annotation).power());
        } else if (annotation instanceof TeacherRoles) {
            role.setCan(user.getRole() >= ((TeacherRoles) annotation).role());
            role.setPower(((TeacherRoles) annotation).power());
        } else if (annotation instanceof AdminRoles) {
            role.setCan(user.getRole() >= ((AdminRoles) annotation).role());
            role.setPower(((AdminRoles) annotation).power());
        }
        return role;
    }

    /**
     * 验证该路由是否需要验证
     * @param action 路由方法
     * @param target 路由所属类
     * @return 验证的注解类型
     */
    private Annotation needAuth(Method action, Class<?> target) {
        Annotation targetAnnotation = hasAnnotation(target.getDeclaredAnnotations());
        if (targetAnnotation != null) {
            IgnoreAuth ignoreAuth = action.getDeclaredAnnotation(IgnoreAuth.class);
            if (ignoreAuth == null) {
                return targetAnnotation;
            }
        } else {
            return hasAnnotation(action.getDeclaredAnnotations());
        }
        return null;
    }

    /**
     * 判断注解中是否含有指定的注解类型
     * @param annotations 注解数组
     * @return 含有的注解，没有null
     */
    private Annotation hasAnnotation(Annotation[] annotations) {
        for (Annotation annotation : annotations) {
            if (annotation instanceof AdminRoles
                    || annotation instanceof TeacherRoles
                    || annotation instanceof StudentRoles) {
                return annotation;
            }
        }
        return null;
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    private class Role {
        // 1 学生，2 老师，3 管理员
        private boolean can;
        private String  power;
    }
}
